using System.Text;
using NUnit.Framework;
using Tycho.Grammar;

namespace Tycho.UnitTests.Grammar {
    [TestFixture]
    public class DeferredCompilationsSpecification {
        [Test]
        public void RunCompilationStepsShouldRunAllDeferredCompilationSteps () {
            var deferredCompilations = new DeferredCompilations ();

            var log = new StringBuilder();

            AddStep (deferredCompilations, log, "one");
            AddStep (deferredCompilations, log, "two");

            Assert.That (log.ToString (), Is.EqualTo (""));

            deferredCompilations.RunCompilationSteps ();

            Assert.That (log.ToString (), Is.EqualTo ("one;two;"));
        }

        [Test]
        public void IfMoreStepsAreAddedWhileStepsAreBeingRunThenThoseShouldBeRunToo () {
            var deferredCompilations = new DeferredCompilations ();

            var log = new StringBuilder();

            deferredCompilations.AddCompilationStep ("one", () => {
                                                         log.Append ("one;");
                                                         AddStep (deferredCompilations, log, "three");
                                                     });
            AddStep (deferredCompilations, log, "two");

            Assert.That (log.ToString (), Is.EqualTo (""));

            deferredCompilations.RunCompilationSteps ();

            Assert.That (log.ToString (), Is.EqualTo ("one;two;three;"));
        }

        [Test]
        public void ShouldExecuteStepForObjectAndRemoveItFromList () {
            var deferredCompilations = new DeferredCompilations ();

            var log = new StringBuilder ();

            AddStep (deferredCompilations, log, "some-object");

            deferredCompilations.RunStepForObject ("some-object");
            Assert.That (log.ToString (), Is.EqualTo ("some-object;"));

            deferredCompilations.RunCompilationSteps ();
            Assert.That (log.ToString (), Is.EqualTo ("some-object;"));
        }

        [Test]
        public void ShouldBeAbleToRunStepWithinStep () {
            var deferredCompilations = new DeferredCompilations ();

            var log = new StringBuilder ();

            AddStep (deferredCompilations, log, "one");
            deferredCompilations.AddCompilationStep ("two", () => {
                                                                deferredCompilations.RunStepForObject ("three");
                                                                log.Append ("two;");
                                                            });
            AddStep (deferredCompilations, log, "three");

            deferredCompilations.RunCompilationSteps ();
            Assert.That (log.ToString (), Is.EqualTo ("one;three;two;"));
        }

        private static void AddStep (IDeferredCompilations deferredCompilations, StringBuilder log, string stepName) {
            deferredCompilations.AddCompilationStep (stepName, () => log.Append (stepName + ";"));
        }

        [Test]
        public void ShouldIgnoreStepIfObjectNotPresent () {
            var deferredCompilations = new DeferredCompilations ();

            deferredCompilations.RunStepForObject ("some-object");
        }
    }
}